package com.hmall.gateway.routes;

import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

/**
 * @Author Mr.Wen
 * @Version 1.0
 * 配置动态路由监听器
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class DynamicRouteLoader {
    private final NacosConfigManager configManager;
    private final RouteDefinitionWriter writer;
    private final String dataId = "gateway-routes.json";
    private final String group = "DEFAULT_GROUP";
    private final Set<String> routeIds = new HashSet<>();

    /**
     * PostConstruct
     * 在bean初始化完成后执行，只执行一次
     */
    @PostConstruct
    public void initRouteConfigListener() throws NacosException {
        String configInfo = configManager.getConfigService()
                .getConfigAndSignListener(dataId, group, 5000, new Listener() {
                    @Override
                    public Executor getExecutor() {
                        return null;
                    }

                    @Override
                    public void receiveConfigInfo(String s) {
//                  监听到配置变更，需要去更新路由表
                    }
                });
//        第一次读取到配置，也需要更新路由表
        updateConfigInfo(configInfo);
    }

    /**
     * 更新路由表
     *
     * @param configInfo
     */
    private void updateConfigInfo(String configInfo) {
        log.info("监听到路由信息:{}", configInfo);
//        TODO 解析配置信息，并转为RouteDefinition
        List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo, RouteDefinition.class);
//            删除旧的路由表
        for (String routeId : routeIds) {
            writer.delete(Mono.just(routeId)).subscribe();
        }
//        更新前清空旧的路由Id表
        routeIds.clear();

//            更新路由表
        for (RouteDefinition routeDefinition : routeDefinitions) {
            writer.save(Mono.just(routeDefinition)).subscribe();
//            记录每一个路由id
            routeIds.add(routeDefinition.getId());
        }
    }
}
